#ifndef __INCLUDED_CBL_TUPLE_H__
#error "CBL_TupleTypes.hpp must not be used directly. Use CBL_Tuple.h instead."
#else
#ifndef __INCLUDED_CBL_TUPLE_TYPES_HPP__
#define __INCLUDED_CBL_TUPLE_TYPES_HPP__

// ---------------------------------------------------------------------------------------------------------------------
//	This file defines convinience classes, derived from CTuple.
//	Classes defined here contain common per-element accessors and permutation functions.
//	Types like Float4 are based on these classes here.
// ---------------------------------------------------------------------------------------------------------------------

#define ACCESSORS2(_A,_B)		CB_FORCEINLINE TType& CB_INLINE_ATTR _A()				{ return (*this)[0]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _A() const	{ return (*this)[0]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _B()				{ return (*this)[1]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _B() const	{ return (*this)[1]; }

#define ACCESSORS3(_A,_B,_C)	CB_FORCEINLINE TType& CB_INLINE_ATTR _A()				{ return (*this)[0]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _A() const	{ return (*this)[0]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _B()				{ return (*this)[1]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _B() const	{ return (*this)[1]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _C()				{ return (*this)[2]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _C() const	{ return (*this)[2]; }

#define ACCESSORS4(_A,_B,_C,_D)	CB_FORCEINLINE TType& CB_INLINE_ATTR _A()				{ return (*this)[0]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _A() const	{ return (*this)[0]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _B()				{ return (*this)[1]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _B() const	{ return (*this)[1]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _C()				{ return (*this)[2]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _C() const	{ return (*this)[2]; } \
								CB_FORCEINLINE TType& CB_INLINE_ATTR _D()				{ return (*this)[3]; } \
								CB_FORCEINLINE const TType& CB_INLINE_ATTR _D() const	{ return (*this)[3]; }

#define PERMUTE2(_A,_B)			CB_FORCEINLINE CTuple<TType,2> CB_INLINE_ATTR _A##_B()			{ return CTuple<TType,2>(_A(),_B()); }
#define PERMUTE3(_A,_B,_C)		CB_FORCEINLINE CTuple<TType,3> CB_INLINE_ATTR _A##_B##_C()		{ return CTuple<TType,3>(_A(),_B(),_C()); }
#define PERMUTE4(_A,_B,_C,_D)	CB_FORCEINLINE CTuple<TType,4> CB_INLINE_ATTR _A##_B##_C##_D()	{ return CTuple<TType,4>(_A(),_B(),_C(),_D()); }

// -------------------------------------------------------------------------------------------------

template <typename TType>
class CTuple2 : public CTuple<TType, 2>
{
public:
	
	CTuple2() : CTuple<TType,2>() {} 
	
	CTuple2(const TType* _pData) : CTuple<TType,2>(_pData) {}
	
	template <typename TType2, uint32 TSize2>
	CTuple2(const CTuple<TType2, TSize2>& _rOther) : CTuple<TType,2>(_rOther) {}
	
	CTuple2(const TType& _rX, const TType& _rY)
	{
		(*this)[0] = _rX;
		(*this)[1] = _rY;
	}
	
public:
	
	ACCESSORS2(X,Y)
	ACCESSORS2(U,V)
	
	PERMUTE2(X,Y)
	PERMUTE2(Y,X)
	
	PERMUTE2(U,V)
	PERMUTE2(V,U)
};

// -------------------------------------------------------------------------------------------------

template <typename TType>
class CTuple3 : public CTuple<TType, 3>
{
public:
	
	CTuple3() : CTuple<TType,3>() {} 
	
	CTuple3(const TType* _pData) : CTuple<TType,3>(_pData) {}
	
	template <typename TType2, uint32 TSize2>
	CTuple3(const CTuple<TType2, TSize2>& _rOther) : CTuple<TType,3>(_rOther) {}
	
	CTuple3(const TType& _rX, const TType& _rY, const TType& _rZ)
	{
		(*this)[0] = _rX;
		(*this)[1] = _rY;
		(*this)[2] = _rZ;
	}

	CTuple3(const CTuple2<TType>& _rOther)
	{
		(*this)[0] = _rOther[0];
		(*this)[1] = _rOther[1];
		(*this)[2] = 0;
	}
	
public:
	
	ACCESSORS3(X,Y,Z)
	ACCESSORS3(R,G,B)
	ACCESSORS3(U,V,W)
	
	PERMUTE3(X,Y,Z)
	PERMUTE3(X,Z,Y)
	PERMUTE3(Y,X,Z)
	PERMUTE3(Y,Z,X)
	PERMUTE3(Z,X,Y)
	PERMUTE3(Z,Y,X)
	
	PERMUTE3(R,G,B)
	PERMUTE3(R,B,G)
	PERMUTE3(G,R,B)
	PERMUTE3(G,B,R)
	PERMUTE3(B,R,G)
	PERMUTE3(B,G,R)
	
	PERMUTE3(U,V,W)
	PERMUTE3(U,W,V)
	PERMUTE3(V,U,W)
	PERMUTE3(V,W,U)
	PERMUTE3(W,U,V)
	PERMUTE3(W,V,U)
};

// -------------------------------------------------------------------------------------------------

template <typename TType>
class CTuple4 : public CTuple<TType, 4>
{
public:
	
	CTuple4() : CTuple<TType,4>() {} 
	
	CTuple4(const TType* _pData) : CTuple<TType,4>(_pData) {}
	
	template <typename TType2, uint32 TSize2>
	CTuple4(const CTuple<TType2, TSize2>& _rOther) : CTuple<TType,4>(_rOther) {}
	
	CTuple4(const TType& _rX, const TType& _rY, const TType& _rZ, const TType& _rW)
	{
		(*this)[0] = _rX;
		(*this)[1] = _rY;
		(*this)[2] = _rZ;
		(*this)[3] = _rW;
	}

	CTuple4(const CTuple3<TType>& _rOther)
	{
		(*this)[0] = _rOther[0];
		(*this)[1] = _rOther[1];
		(*this)[2] = _rOther[2];
		(*this)[3] = 1;
	}

	CTuple4(const CTuple2<TType>& _rOther)
	{
		(*this)[0] = _rOther[0];
		(*this)[1] = _rOther[1];
		(*this)[2] = 0;
		(*this)[3] = 1;
	}
	
public:
	
	ACCESSORS4(X,Y,Z,W)
	ACCESSORS4(R,G,B,A)
	
	PERMUTE4(X,Y,Z,W)
	PERMUTE4(X,Z,Y,W)
	PERMUTE4(Y,X,Z,W)
	PERMUTE4(Y,Z,X,W)
	PERMUTE4(Z,X,Y,W)
	PERMUTE4(Z,Y,X,W)
	
	PERMUTE4(X,Y,W,Z)
	PERMUTE4(X,Z,W,Y)
	PERMUTE4(Y,X,W,Z)
	PERMUTE4(Y,Z,W,X)
	PERMUTE4(Z,X,W,Y)
	PERMUTE4(Z,Y,W,X)
	
	PERMUTE4(X,W,Y,Z)
	PERMUTE4(X,W,Z,Y)
	PERMUTE4(Y,W,X,Z)
	PERMUTE4(Y,W,Z,X)
	PERMUTE4(Z,W,X,Y)
	PERMUTE4(Z,W,Y,X)
	
	PERMUTE4(W,X,Y,Z)
	PERMUTE4(W,X,Z,Y)
	PERMUTE4(W,Y,X,Z)
	PERMUTE4(W,Y,Z,X)
	PERMUTE4(W,Z,X,Y)
	PERMUTE4(W,Z,Y,X)
	
	PERMUTE4(R,G,B,A)
	PERMUTE4(R,B,G,A)
	PERMUTE4(G,R,B,A)
	PERMUTE4(G,B,R,A)
	PERMUTE4(B,R,G,A)
	PERMUTE4(B,G,R,A)
	
	PERMUTE4(R,G,A,B)
	PERMUTE4(R,B,A,G)
	PERMUTE4(G,R,A,B)
	PERMUTE4(G,B,A,R)
	PERMUTE4(B,R,A,G)
	PERMUTE4(B,G,A,R)
	
	PERMUTE4(R,A,G,B)
	PERMUTE4(R,A,B,G)
	PERMUTE4(G,A,R,B)
	PERMUTE4(G,A,B,R)
	PERMUTE4(B,A,R,G)
	PERMUTE4(B,A,G,R)
	
	PERMUTE4(A,R,G,B)
	PERMUTE4(A,R,B,G)
	PERMUTE4(A,G,R,B)
	PERMUTE4(A,G,B,R)
	PERMUTE4(A,B,R,G)
	PERMUTE4(A,B,G,R)
};

#endif
#endif
